﻿#include <vector>
#include <QStandardItem>
#include <QFileDialog>
#include <QMessageBox>
#include <QAxObject>

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "easylogging++.h"
#include "AreaIdentify.h"

MainWindow::MainWindow(QWidget* parent) :
	QMainWindow(parent),
	ui(new Ui::MainWindow)
{
	ui->setupUi(this);

	initWindowElement();
	conectSignalSlot();
}

MainWindow::~MainWindow()
{
	delete ui;
}

void MainWindow::initSerialPort() {
	this->serialPort = std::make_shared<SerialPort>(*this);
	auto allPorts = this->serialPort->findFreePorts();
	for (auto&& name : allPorts) {
		ui->comNoValueComboBox->addItem(name);
	}
}

void MainWindow::initWindowElement() {
	initSerialPort();

	this->areaIdentify = std::make_shared<AreaIdentify>(*this, this->serialPort);
	this->phaseIdentify = std::make_shared<PhaseIdentify>(*this, this->serialPort);
	this->searchTable = std::make_shared<SearchTable>(*this, this->serialPort);

	ui->functionaListTreeWidget->setHeaderLabel("功能导航");
	QTreeWidgetItem* item1 = new QTreeWidgetItem(ui->functionaListTreeWidget, QStringList("台区识别"));
	QTreeWidgetItem* item2 = new QTreeWidgetItem(ui->functionaListTreeWidget, QStringList("相位识别"));
	QTreeWidgetItem* item3 = new QTreeWidgetItem(ui->functionaListTreeWidget, QStringList("搜表"));
	ui->functionaListTreeWidget->setStyleSheet(
		"QTreeWidget::item{height:35px;}"
	);
	ui->functionalAreaStackedWidget->setCurrentIndex(0);

	ui->startAreaIdentifyPushButton->setEnabled(false);
	ui->stopAreaIdentifyPushButton->setEnabled(false);
	ui->getAreaIdentifyResultPushButton->setEnabled(false);
	ui->exportAreaIdentifyResultPushButton->setEnabled(true);
	ui->startSearchTablePushButton->setEnabled(false);
	ui->stopSearchTablePushButton->setEnabled(false);
	ui->getSearchTableResultPushButton->setEnabled(false);
	ui->exportSearchTableResultPushButton->setEnabled(true);
	ui->exportPhaseIdentifyResultPushButton->setEnabled(true);
	ui->startPhaseIdentifyPushButton->setEnabled(false);

	this->areaIdentifyResultViewModel = new QStandardItemModel(ui->areaIdentifyResultViewTreeView);
	this->areaIdentifyResultViewModel->setHorizontalHeaderLabels(QStringList() << QStringLiteral("电表地址") << QStringLiteral("是否本台区") << QStringLiteral("所属台区"));
	ui->areaIdentifyResultViewTreeView->setModel(this->areaIdentifyResultViewModel);
	ui->areaIdentifyResultViewTreeView->header()->setSectionResizeMode(QHeaderView::Stretch);

	initPhaseIdentifyResultView();

	this->searchTableResultViewModel = new QStandardItemModel(ui->searchTableResultViewTreeView);
	this->searchTableResultViewModel->setHorizontalHeaderLabels(QStringList() << QStringLiteral("电表地址"));
	ui->searchTableResultViewTreeView->setModel(this->searchTableResultViewModel);
	ui->searchTableResultViewTreeView->header()->setSectionResizeMode(QHeaderView::Stretch);
}

void MainWindow::initPhaseIdentifyResultView() {
	this->phaseIdentifyResultViewModel = new QStandardItemModel(ui->phaseIdentifyResultViewTreeView);
	this->phaseIdentifyResultViewModel->setHorizontalHeaderLabels(QStringList() << QStringLiteral("电表地址") << QStringLiteral("相序类型") << QStringLiteral("物理相位") << QStringLiteral("相位数量统计"));
	ui->phaseIdentifyResultViewTreeView->setModel(this->phaseIdentifyResultViewModel);
	ui->phaseIdentifyResultViewTreeView->header()->setSectionResizeMode(QHeaderView::Stretch);

	for (auto&& title : phaseStatisticsTitle) {
		QList<QStandardItem*> items;
		QStandardItem* item1 = new QStandardItem("");
		QStandardItem* item2 = new QStandardItem("");
		QStandardItem* item3 = new QStandardItem("");
		QStandardItem* item4 = new QStandardItem(title + QString::number(0));
		items.append(item1);
		items.append(item2);
		items.append(item3);
		items.append(item4);
		this->phaseIdentifyResultViewModel->appendRow(items);
	}
}

void MainWindow::conectSignalSlot() {
	connect(ui->functionaListTreeWidget, &QTreeWidget::itemClicked, this, &MainWindow::handleFunctionaListTreeWidgetItemClicked);

	connect(ui->comNoCheckBox, &QCheckBox::toggled, this, &MainWindow::handleComNoCheckBoxToggled);

	connect(ui->startAreaIdentifyPushButton, &QPushButton::clicked, [=]() {
		this->areaIdentify->sendStartAreaIdentify();
		});
	connect(ui->getAreaIdentifyResultPushButton, &QPushButton::clicked, [=]() {
		this->areaIdentify->sendQueryTableFileAreaResult();
		this->areaIdentify->sendQueryRedundantAreaResult();
		// this->areaIdentify->startQueryAreaResultTimer(60000 * 2);
		});
	connect(ui->exportAreaIdentifyResultPushButton, &QPushButton::clicked, [=]() {
		exportAreaIdentifyResult();
		});
	connect(ui->startPhaseIdentifyPushButton, &QPushButton::clicked, [=]() {
		this->phaseIdentify->sendQueryNodeNumber();
		});
	connect(ui->exportPhaseIdentifyResultPushButton, &QPushButton::clicked, [=]() {
		exportPhaseIdentifyResult();
		});
	connect(ui->startSearchTablePushButton, &QPushButton::clicked, [=]() {
		this->searchTable->sendStartSearchTable();
		});
	connect(ui->stopSearchTablePushButton, &QPushButton::clicked, [=]() {
		this->searchTable->sendStopSearchTable();
		});
	connect(ui->getSearchTableResultPushButton, &QPushButton::clicked, [=]() {
		this->searchTable->sendQueryNodeInfo();
		});
	connect(ui->exportSearchTableResultPushButton, &QPushButton::clicked, [=]() {
		exportSearchTableResult();
		});
}

void MainWindow::updateAreaViewModel(const QString& nodeAddr, const QString& nodeStatus, const QString& terminalNo) {
	LOG(INFO) << "nodeAddr:" << nodeAddr.toStdString() << ", nodeStatus:" << nodeStatus.toStdString();
	auto&& items = this->areaIdentifyResultViewModel->findItems(nodeAddr, Qt::MatchExactly, 0);
	if (items.size() > 1) {
		LOG(ERROR) << "have more than one node, " << "nodeAddr:" << nodeAddr.toStdString() << ", nodeStatus:" << nodeStatus.toStdString();
		return;
	}
	else if (items.size() == 1) {
		auto row = (*(items.begin()))->row();
		auto col = (*(items.begin()))->column();
		auto isLocalItemIndex = this->areaIdentifyResultViewModel->index(row, col + 1);
		this->areaIdentifyResultViewModel->setData(isLocalItemIndex, nodeStatus);
		auto areaNoIndex = this->areaIdentifyResultViewModel->index(row, col + 2);
		this->areaIdentifyResultViewModel->setData(areaNoIndex, terminalNo);
	}
	else {
		QList<QStandardItem*> items1;
		QStandardItem* item1 = new QStandardItem(nodeAddr);
		QStandardItem* item2 = new QStandardItem(nodeStatus);
		QStandardItem* item3 = new QStandardItem(terminalNo);
		items1.append(item1);
		items1.append(item2);
		items1.append(item3);
		this->areaIdentifyResultViewModel->appendRow(items1);
	}
}

void MainWindow::exportAreaIdentifyResult() {
	LOG(INFO) << "exportAreaIdentifyResult begin.";
	saveToExcel(this->areaIdentifyResultViewModel, 3);
	LOG(INFO) << "exportAreaIdentifyResult end.";
}

void MainWindow::updatePhaseViewModel(const QString& nodeAddr, const QString& phaseSequenceType, const QString& physicalPhase, const std::vector<uint32_t>& phaseCnt) {
	std::ostringstream oss;
	uint32_t totalCnt = 0;
	for (int i = 0; i < phaseStatisticsTitle.size(); ++i) {
		auto phaseCntItemIndex = this->phaseIdentifyResultViewModel->index(i, 3);
		this->phaseIdentifyResultViewModel->setData(phaseCntItemIndex, phaseStatisticsTitle[i] + QString::number(phaseCnt[i]));
		totalCnt += phaseCnt[i];
		oss << phaseCnt[i] << ",";
	}
	LOG(INFO) << "nodeAddr:" << nodeAddr.toStdString() << ", phaseSequenceType:" << phaseSequenceType.toStdString() << ", physicalPhase:" << physicalPhase.toStdString() << ", phaseCnt:" << oss.str();

	auto&& items = this->phaseIdentifyResultViewModel->findItems(nodeAddr, Qt::MatchExactly, 0);
	if (items.size() > 1) {
		LOG(ERROR) << "have more than one node, " << "nodeAddr:" << nodeAddr.toStdString();
		return;
	}
	else if (items.size() == 1) {
		LOG(INFO) << "have find nodeAddr:" << nodeAddr.toStdString();
		// 更新
		auto row = (*(items.begin()))->row();
		auto col = (*(items.begin()))->column();
		auto phaseSequenceTypeIndex = this->areaIdentifyResultViewModel->index(row, col + 1);
		this->areaIdentifyResultViewModel->setData(phaseSequenceTypeIndex, phaseSequenceType);
		auto physicalPhaseIndex = this->areaIdentifyResultViewModel->index(row, col + 2);
		this->areaIdentifyResultViewModel->setData(physicalPhaseIndex, physicalPhase);
	}
	else {
		LOG(INFO) << "new add nodeAddr:" << nodeAddr.toStdString();
		// 增加
		if (totalCnt <= 5) {
			auto itemIndex = this->phaseIdentifyResultViewModel->index(totalCnt - 1, 0);
			this->phaseIdentifyResultViewModel->setData(itemIndex, nodeAddr);
			itemIndex = this->phaseIdentifyResultViewModel->index(totalCnt - 1, 1);
			this->phaseIdentifyResultViewModel->setData(itemIndex, phaseSequenceType);
			itemIndex = this->phaseIdentifyResultViewModel->index(totalCnt - 1, 2);
			this->phaseIdentifyResultViewModel->setData(itemIndex, physicalPhase);
		}
		else {
			QList<QStandardItem*> items;
			QStandardItem* item1 = new QStandardItem(nodeAddr);
			QStandardItem* item2 = new QStandardItem(phaseSequenceType);
			QStandardItem* item3 = new QStandardItem(physicalPhase);
			QStandardItem* item4 = new QStandardItem("");
			items.append(item1);
			items.append(item2);
			items.append(item3);
			items.append(item4);
			this->phaseIdentifyResultViewModel->appendRow(items);
		}
	}
}

void MainWindow::exportPhaseIdentifyResult() {
	LOG(INFO) << "exportPhaseIdentifyResult begin.";
	saveToExcel(this->phaseIdentifyResultViewModel, 4);
	LOG(INFO) << "exportPhaseIdentifyResult end.";
}

void MainWindow::updateSearchTableViewModel(const QString& nodeAddr) {
	LOG(INFO) << "nodeAddr:" << nodeAddr.toStdString();
	auto&& items = this->searchTableResultViewModel->findItems(nodeAddr, Qt::MatchExactly, 0);
	if (items.size() >= 1) {
		LOG(ERROR) << "have node, " << "nodeAddr:" << nodeAddr.toStdString();
		return;
	}
	items.clear();
	QStandardItem* item1 = new QStandardItem(nodeAddr);
	items.append(item1);
	this->searchTableResultViewModel->appendRow(items);
}

void MainWindow::exportSearchTableResult() {
	LOG(INFO) << "exportSearchTableResult begin.";
	saveToExcel(this->searchTableResultViewModel, 1);
	LOG(INFO) << "exportSearchTableResult end.";
}

void MainWindow::saveToExcel(QStandardItemModel* model, int columnNum) {
	try {
		LOG(INFO) << "model:" << model << " columnNum:" << columnNum;
		QString filepath = QFileDialog::getSaveFileName(this, tr("Save"), ".", tr(" (*.xlsx)"));
		LOG(INFO) << "filepath:" << filepath.toStdString();
		if (!filepath.isEmpty()) {
			QAxObject* excel = new QAxObject(this);
			LOG(INFO) << "excel:" << excel;
			//连接Excel控件
			excel->setControl("Excel.Application");
			LOG(INFO) << R"(excel->setControl("Excel.Application");)";
			//不显示窗体
			excel->dynamicCall("SetVisible (bool Visible)", "false");
			LOG(INFO) << R"=(excel->dynamicCall("SetVisible (bool Visible)", "false");)=";
			//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改，是否保存”的提示
			excel->setProperty("DisplayAlerts", false);
			LOG(INFO) << R"=(excel->setProperty("DisplayAlerts", false);)=";
			//获取工作簿集合
			QAxObject* workbooks = excel->querySubObject("WorkBooks");
			LOG(INFO) << R"=(workbooks:)=" << workbooks;
			//新建一个工作簿
			workbooks->dynamicCall("Add");
			LOG(INFO) << R"=(workbooks->dynamicCall("Add");)=";
			//获取当前工作簿
			QAxObject* workbook = excel->querySubObject("ActiveWorkBook");
			LOG(INFO) << R"=(workbook:)=" << workbook;
			//获取工作表集合
			QAxObject* worksheets = workbook->querySubObject("Sheets");
			LOG(INFO) << R"=(worksheets:)=" << worksheets;
			//获取工作表集合的工作表1，即sheet1
			QAxObject* worksheet = worksheets->querySubObject("Item(int)", 1);
			LOG(INFO) << R"=(worksheet:)=" << worksheet;

			std::vector<QString> cellPrefixNames;
			LOG(INFO) << R"=(std::vector<QString> cellPrefixNames;)=";
			for (int i = 0; i < columnNum; ++i) {
				LOG(INFO) << "i:" << i << " columnNum:" << columnNum;
				QString prefixName;
				LOG(INFO) << R"=(QString prefixName;)=";
				prefixName.append(QChar('A' + i));
				LOG(INFO) << R"=(prefixName:)=" << prefixName.toStdString();
				cellPrefixNames.push_back(prefixName);
				LOG(INFO) << R"=(cellPrefixNames.push_back(prefixName);)=";
			}
			//设置标题
			int cellrow = 1;
			LOG(INFO) << R"=(cellrow:)=" << cellrow;
			std::vector<QString> cellNames;
			for (int i = 0; i < columnNum; ++i) {
				LOG(INFO) << "i:" << i << " columnNum:" << columnNum;
				auto name = cellPrefixNames[i] + QString::number(cellrow);
				LOG(INFO) << "name:" << name.toStdString();
				auto* cell = worksheet->querySubObject("Range(QVariant, QVariant)", name);
				LOG(INFO) << "cell:" << cell;
				cell->dynamicCall("SetValue(const QVariant&)", QVariant(model->horizontalHeaderItem(i)->text()));
				LOG(INFO) << R"=(cell->dynamicCall("SetValue(const QVariant&)", QVariant(model->horizontalHeaderItem(i)->text()));)=";
			}
			cellrow++;
			LOG(INFO) << "cellrow:" << cellrow;
			int rows = model->rowCount();
			LOG(INFO) << "rows:" << rows;
			// 设置表格数据
			for (int i = 0; i < rows; i++) {
				// LOG(INFO) << "i:" << i << " rows:" << rows;
				for (int j = 0; j < columnNum; ++j) {
					LOG(INFO) << "j:" << j << " columnNum:" << columnNum;
					auto name = cellPrefixNames[j] + QString::number(cellrow);
					LOG(INFO) << "name:" << name.toStdString();
					auto* cell = worksheet->querySubObject("Range(QVariant, QVariant)", name);
					LOG(INFO) << "cell:" << cell;
					cell->setProperty("NumberFormatLocal", "@");
					LOG(INFO) << R"=(cell->setProperty("NumberFormatLocal", "@");)=";
					cell->dynamicCall("SetValue(const QVariant&)", QVariant(model->item(i, j)->data(Qt::DisplayRole).toString()));
					LOG(INFO) << R"=(cell->dynamicCall("SetValue(const QVariant&)", QVariant(model->item(i, j)->data(Qt::DisplayRole).toString()));)=";
				}
				cellrow++;
				LOG(INFO) << "cellrow:" << cellrow;
			}

			workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(filepath));//保存至filepath，注意一定要用QDir::toNativeSeparators将路径中的"/"转换为"\"，不然一定保存不了。
			LOG(INFO) << R"=(workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(filepath));)=";
			workbook->dynamicCall("Close()");//关闭工作簿
			LOG(INFO) << R"=(workbook->dynamicCall("Close()");)=";
			excel->dynamicCall("Quit()");//关闭excel
			LOG(INFO) << R"=(excel->dynamicCall("Quit()"); excel:)=" << excel;
			delete excel;
			LOG(INFO) << R"=(delete excel;)=";
			excel = NULL;
			LOG(INFO) << "\n导出成功啦！！！excel:" << excel;
		}
	}
	catch (std::runtime_error& e) {
		LOG(ERROR) << "exception: " << e.what();
	}
	catch (std::runtime_error* e) {
		LOG(ERROR) << "exception: " << e->what();
	}
	catch (std::exception& e) {
		LOG(ERROR) << "exception: " << e.what();
	}
}

Ui::MainWindow* MainWindow::getUi() {
	return ui;
}

std::shared_ptr<AreaIdentify> MainWindow::getAreaIdentify() {
	return areaIdentify;
}

std::shared_ptr<PhaseIdentify> MainWindow::getPhaseIdentify() {
	return phaseIdentify;
}

std::shared_ptr<SearchTable> MainWindow::getSearchTable() {
	return searchTable;
}

void MainWindow::receiveLogin() {
	this->show();
}

void MainWindow::handleComNoCheckBoxToggled(bool checked) {
	if (checked) {
		this->serialPort->init(ui->comNoValueComboBox->currentText());

		this->serialPort->startWaitConfirmTimer(1000);
		this->areaIdentify->sendQueryTerminalNo();
		ui->terminalNoValueLabel->setText("获取终端编号中，请等待...");
	}
	else {
		this->serialPort->close();
		ui->startAreaIdentifyPushButton->setEnabled(false);
		ui->stopAreaIdentifyPushButton->setEnabled(false);
		ui->getAreaIdentifyResultPushButton->setEnabled(false);
		ui->exportAreaIdentifyResultPushButton->setEnabled(true);
		ui->startSearchTablePushButton->setEnabled(false);
		ui->stopSearchTablePushButton->setEnabled(false);
		ui->getSearchTableResultPushButton->setEnabled(false);
		ui->exportSearchTableResultPushButton->setEnabled(false);
		ui->exportPhaseIdentifyResultPushButton->setEnabled(false);
		ui->startPhaseIdentifyPushButton->setEnabled(false);
		ui->comNoCheckBox->setChecked(false);
		ui->terminalNoValueLabel->setText("");
	}
}

void MainWindow::handleFunctionaListTreeWidgetItemClicked(QTreeWidgetItem* item, int column) {
	if (item->text(0) == QString("台区识别")) {
		ui->functionalAreaStackedWidget->setCurrentIndex(0);
	}
	else if (item->text(0) == QString("相位识别")) {
		ui->functionalAreaStackedWidget->setCurrentIndex(1);
	}
	else if (item->text(0) == QString("搜表")) {
		ui->functionalAreaStackedWidget->setCurrentIndex(2);
	}
}




